package com.faithbj.process.impl;

import com.faithbj.common.model.CheckTotal;
import com.faithbj.common.model.compare.*;
import com.faithbj.common.model.fm.FamilyMember;
import com.faithbj.common.model.fm.FamilyMemberIncome;
import com.faithbj.common.model.fm.property.FamilyMemberProperty;
import com.faithbj.common.model.fm.verify.FamilyMemberIncomeVerify;
import com.faithbj.common.model.fm.verify.FamilyMemberPropertyVerify;
import com.faithbj.common_service.dao.FamilyMemberIncomeVerifyDao;
import com.faithbj.common_service.dao.FamilyMemberPropertyVerifyDao;
import com.faithbj.common_service.service.CompareService;
import com.faithbj.common_service.service.FamilyMemberPropertyService;
import com.faithbj.common_service.service.FamilyMemberService;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.process.WorkItem;
import org.drools.runtime.process.WorkItemHandler;
import org.drools.runtime.process.WorkItemManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.util.List;

/**
 * User: xiongyuanwei
 * Date: 12-7-31
 * Time: 下午11:01
 */
@Component
public class CalculateWorkItemHandler implements WorkItemHandler {

    private static Logger log = LoggerFactory.getLogger(CalculateWorkItemHandler.class);

    @Autowired
    private CompareService compareService;

    @Autowired
    private FamilyMemberService familyMemberService;

    @Autowired
    private FamilyMemberPropertyService familyMemberPropertyService;

    @Autowired
    private FamilyMemberIncomeVerifyDao familyMemberIncomeVerifyDao;

    @Autowired
    private FamilyMemberPropertyVerifyDao familyMemberPropertyVerifyDao;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    @Autowired
    private StatefulKnowledgeSession ksession;

    @PostConstruct
    protected void init() {
        ksession.getWorkItemManager().registerWorkItemHandler("Calculate", this);
    }

    @Override
    @Transactional
    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
        CheckTotal checkTotal = (CheckTotal) workItem.getParameter("checkTotal");
        String applyId = checkTotal.getId();
        List<FamilyMember> familyMembers = familyMemberService.getFamilyMembersByCheckTotal(applyId);
        for (FamilyMember fm : familyMembers) {
            String idNum = fm.getIdNumber();
            FamilyMemberIncome income = fm.getIncome();
            AFMOfficalData data1 = compareService.getAFMOfficalData(idNum, applyId);
            CivilOfficalData data2 = compareService.getCivilOfficalData(idNum, applyId);
            HPOfficalData data3 = compareService.getHPOfficalData(idNum, applyId);
            IBAOfficalData data4 = compareService.getIBAOfficalData(idNum, applyId);
            PopulationOfficalData data5 = compareService.getPSOfficalData(idNum, applyId);
            SIOfficalData data6 = compareService.getSIOfficalData(idNum, applyId);
            TaxOfficalData data7 = compareService.getTaxOfficalData(idNum, applyId);
            FamilyMemberIncomeVerify incomeVerifyData = generateVerifyData(income, data1, data2, data3, data4, data5, data6, data7);
            familyMemberIncomeVerifyDao.save(incomeVerifyData);
            // TODO FamilyMemberPropertyVerify 就靠你来存了，神
            FamilyMemberProperty property = new FamilyMemberProperty();
            FamilyMemberPropertyVerify propertyVerifyData = generatePropertyVerifyData(property, data1, data2, data3, data4, data5, data6, data7);
            familyMemberPropertyVerifyDao.save(propertyVerifyData);
        }
        manager.completeWorkItem(workItem.getId(), null);
    }

    @Override
    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
        // cannot be aborted
    }

    private FamilyMemberIncomeVerify generateVerifyData(FamilyMemberIncome income, AFMOfficalData data1,
            CivilOfficalData data2, HPOfficalData data3, IBAOfficalData data4, PopulationOfficalData data5,
            SIOfficalData data6, TaxOfficalData data7) {
        FamilyMemberIncomeVerify result = new FamilyMemberIncomeVerify();
        result.setAssistantIncome(add(data2.getLowIncomeAidMoney(), data2.getSpecialCareAidMoney()));
        // TODO please populate the result object
        return populateWithZeros(result, FamilyMemberIncomeVerify.class);
    }

    private FamilyMemberPropertyVerify generatePropertyVerifyData(FamilyMemberProperty property, AFMOfficalData data1,
                                                        CivilOfficalData data2, HPOfficalData data3, IBAOfficalData data4, PopulationOfficalData data5,
                                                        SIOfficalData data6, TaxOfficalData data7) {
        FamilyMemberPropertyVerify result = new FamilyMemberPropertyVerify();
        // TODO please populate the result object
        return populateWithZeros(result, FamilyMemberPropertyVerify.class);
    }

    private BigDecimal add(BigDecimal n1, BigDecimal n2) {
        if (n1 == null) n1 = BigDecimal.ZERO;
        if (n2 == null) n2 = BigDecimal.ZERO;
        return n1.add(n2);
    }

    private <T> T populateWithZeros(T obj, Class<T> cls) {
        for (PropertyDescriptor property : BeanUtils.getPropertyDescriptors(cls)) {
            if (property.getPropertyType().isAssignableFrom(BigDecimal.class)) {
                try {
                    Object value = property.getReadMethod().invoke(obj);
                    if (value == null) {
                        property.getWriteMethod().invoke(obj, BigDecimal.ZERO);
                    }
                } catch (Exception e) {
                    log.warn("Cannot set property '{}' of object {} to zero.", property.getName(), obj);
                }
            }
        }
        return obj;
    }
}
